
#include "h_mempool.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 添加一个内存块到内存池
static void h_mempool_add(h_mempool_t *m, chunk_t * node) {
    if (m == NULL || node == NULL) {
        return;
    }
    if (m->tail == NULL) {
        m->head = node;
        m->tail = node;
    } else {
        m->tail->next = node;
        m->tail = node;    
    }
}

h_mempool_t *h_mempool_new() {
   return calloc(1, sizeof(h_mempool_t));
}

bool h_mempool_init(h_mempool_t *m, uint32_t total, uint32_t expand_num, uint32_t chunk_size) {
    if (m == NULL || total == 0 || chunk_size == 0) {
        return false;
    }
    if (m->total > 0) {
        return false;
    }
    for (int i = 0; i < total; i++) {
        chunk_t *node = (chunk_t *)calloc(1, sizeof(chunk_t) + chunk_size);
        if (node == NULL) {
            return false;
        }
        node->size = chunk_size;
        h_mempool_add(m, node);
    }

    m->total = total;
    m->used = 0;
    m->chunk_size = chunk_size;
    m->expand_num = expand_num;
    return true;
}

// 获取内存块
void *h_mempool_get(h_mempool_t *m) {
    if (m == NULL) {
        return NULL;
    }
    if (m->total == m->used) {
        if (m->expand_num > 0) {
            for (int i = 0; i < m->expand_num; i++) {
                chunk_t *node = calloc(1, sizeof(chunk_t) + m->chunk_size);
                if (node == NULL) {
                    return NULL;
                }
                node->size = m->chunk_size;
                h_mempool_add(m, node);
            }
            m->total += m->expand_num;
            chunk_t *node = m->head;
            m->head = node->next;
            if (node == m->tail) {
                m->tail = m->head;
            }
            node->next = NULL;
            ++m->used;
            return node->data;
        }
        return NULL;
    }
    chunk_t *node = m->head;
    m->head = node->next;
    if (node == m->tail) {
        m->tail = m->head;
    }
    node->next = NULL;
    ++m->used;
    return node->data;
}

// 回收内存块
void h_mempool_put(h_mempool_t *m, void *data) {
    if (m == NULL || data == NULL) {
        return;
    }
    chunk_t * node = (chunk_t *)((uint8_t *)data - sizeof(chunk_t));
    if (m == NULL || node == NULL) {
        return;
    }
    if (m->tail == NULL) {
        m->head = node;
        m->tail = node;
    } else {
        m->tail->next = node;
        m->tail = node;
    }
    --m->used;
}

// 清空内存池
void h_mempool_clear(h_mempool_t *m) {
    if (m == NULL) {
        return;
    }
    chunk_t *node = m->head;
    while (node != NULL) {
        chunk_t *temp = node;
        node = node->next;
        free(temp);
    }
    memset(m, 0, sizeof(h_mempool_t));
}

// 销毁内存池
void h_mempool_destroy(h_mempool_t *m) {
    if (m == NULL) {
        return;
    }
    h_mempool_clear(m);
    free(m);
}

void h_mempool_print(h_mempool_t *m, bool detail) {
    if (m == NULL) {
        return;
    }
    printf("mempool total %u used %u\n", m->total, m->used);
    printf("mempool expand_num %u chunk_size %u\n", m->expand_num, m->chunk_size);
    if (detail) {
        chunk_t *node = m->head;
        while (node != NULL) {
            printf("print chunk:%p\n", node);
            node = node->next;        
        }   
    }
}